package uk.ac.glasgow.demosocs.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import uk.ac.glasgow.demosocs.Candidate;
import uk.ac.glasgow.demosocs.Election;
import uk.ac.glasgow.demosocs.ElectionResult;
import uk.ac.glasgow.demosocs.ElectionState;
import uk.ac.glasgow.demosocs.users.User;
import uk.ac.glasgow.demosocs.users.UserStoreImpl;
import uk.ac.glasgow.demosocs.users.Voter;

/**
 * The Class ElectionStub.
 */
public class ElectionStub implements Election{

	/** The election results. */
	private ElectionResult electionResults;

	/** The election state. */
	private ElectionState electionState = ElectionState.NOT_STARTED;

	/** The candidates. */
	private Set<Candidate> candidates;

	/** The electorate. */
	private Set<Voter> electorate;

	/** A list with all the votes from this election */
	private List<String> votes = new ArrayList<String>();

	/** The name. */
	private String name;

	/** The type id. */
	private String typeID;

	/** The EID. */
	private String EID;

	/** The manager. */
	private String manager;

	/** The start. */
	private Date start;

	/** The end. */
	private Date end;

	/** The open nomination time. */
	private Date openNomTime;

	public String toString(){
		//build all the necessary Strings
		String electorateString = "";
		System.out.println("Creating electorate string.");
		for (Voter voter : electorate){
			electorateString += voter.toString() + " ";
		}
		String candidatesString = "";
		System.out.println("Creating candidates string.");
		for (Candidate candidate : candidates){
			candidatesString += candidate.toString() + " ";
		}
		String votesString = "";
		System.out.println("Creating voters string.");
		for (String vote : votes){
			votesString += vote.toString() + " ";
		}
		//construct the date strings
		SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");
		//dateFormat.
		StringBuilder openNomTimeString = new StringBuilder(dateFormat.format(openNomTime));
		StringBuilder startString = new StringBuilder(dateFormat.format(start));
		StringBuilder endString = new StringBuilder(dateFormat.format(end));
		

		//build the string
		String election = "";
		System.out.println("Creating main string.");
		election = EID + " " + name + " " + " " + typeID + " " + manager + " " + openNomTimeString
		+ " " + startString + " " + endString + " " + electionState + " " +
		electorate.size() + " " + electorateString + " " +
		candidates.size() + " " + candidatesString + " " +
		votes.size() + " " + votesString + " " +
		electionResults.getWinningCandidates().size() + " " + electionResults.toString();


		System.out.println("Returning election string of:");
		System.out.println(election + "\n");
		return election;
	}


	/**
	 * Instantiates a new election stub.
	 *
	 * @param name the name
	 * @param typeID the type id
	 */
	public ElectionStub(String name, String typeID){
		this.name = name;
		this.typeID = typeID;
		this.candidates = new HashSet<Candidate>();
		this.electorate = new HashSet<Voter>();
		this.votes = new ArrayList<String>();
		this.manager = null;
		this.electionResults = new ElectionResultStub();
	}


	/**
	 * Instantiates a new election stub.
	 *
	 * @param election the election
	 */
	public ElectionStub(ElectionStub election){
		this.EID = election.getEID();
		this.start = election.getStart();
		this.end = election.getEnd();
		this.name = election.getName();
		this.openNomTime = election.getOpenNominations();
	}

	/**
	 * Instantiates a new election stub.
	 *
	 * @param election the election
	 */
	public ElectionStub(Election election){
		this.EID = election.getEID();
		this.start = election.getStart();
		this.end = election.getEnd();
		this.openNomTime = election.getOpenNominations();
	}
	
	public ElectionStub(String EID, String electionName, String type, String manager, Date openNomTime, Date start,
			Date end, ElectionState state, Set<Voter> electorate, Set<Candidate> candidates, List<String> votes,
			ElectionResult results){
		this.EID = EID;
		this.name = electionName;
		this.typeID = type;
		this.manager = manager;
		this.openNomTime = openNomTime;
		this.start = start;
		this.end = end;
		this.electionState = state;
		this.electorate = electorate;
		this.candidates = candidates;
		this.votes = votes;
		this.electionResults = results;
	}


	/**
	 * Adds the candidate.
	 *
	 * @param user the user
	 */
	public void addCandidate(User user){
		Candidate candidate = new CandidateStub(user.getSurname(), user.getForename(), user.getGUID());

		candidates.add(candidate);
	}

	/**
	 * Adds the candidate.
	 *
	 * @param candidate the candidate
	 */
	public void addCandidate(Candidate candidate){
		candidates.add(candidate);
	}

	public void addCandidate(Voter voter){
		Candidate candidate = new CandidateStub(voter.getSurname(), voter.getForename(), voter.getGUID());
		candidates.add(candidate);
	}


	public String getManager() {
		return manager;
	}


	public void setManager(String manager) {
		this.manager = manager;
	}


	/**
	 * Gets the name.
	 *
	 * @return the name
	 */
	public String getName() {
		return name;
	}


	/**
	 * Sets the name.
	 *
	 * @param name the new name
	 */
	public void setName(String name) {
		this.name = name;
	}


	/**
	 * Gets the type id.
	 *
	 * @return the type id
	 */
	public String getTypeID() {
		return typeID;
	}


	/**
	 * Sets the type id.
	 *
	 * @param typeID the new type id
	 */
	public void setTypeID(String typeID) {
		this.typeID = typeID;
	}


	/**
	 * Gets the election ID.
	 * 
	 * @return election ID
	 */
	@Override
	public String getEID() {		
		return this.EID;
	}

	/**
	 * Sets the eID.
	 *
	 * @param eID the new eID
	 */
	public void setEID(String eID) {
		this.EID = eID;
	}

	/**
	 * Gets the election result
	 * 
	 * @return the result of the election
	 */
	@Override
	public ElectionResult getElectionResult() {
		return (this.electionState == ElectionState.PUBLISHED ? 
				this.electionResults : null); 
	}

	/**
	 * Sets the election result.
	 *
	 * @param results the new election result
	 */
	public void setElectionResult(ElectionResult results){
		this.electionResults = results;
	}

	/**
	 * Gets the election state
	 * 
	 * @return the election state
	 * 
	 */
	@Override
	public ElectionState getElectionState() {
		return this.electionState;
	}

	/**
	 * Sets the election state.
	 *
	 * @param state the new election state
	 */
	public void setElectionState(ElectionState state){
		this.electionState = state;
	}

	/**
	 * Gets the candidates
	 * 
	 * @return the candidates
	 */
	@Override
	public Set<Candidate> getCandidates() {
		return this.candidates;
	}

	/**
	 * Sets the candidates.
	 *
	 * @param candidates the new candidates
	 */
	public void setCandidates(Set<Candidate> candidates){
		this.candidates = candidates;
	}

	/**
	 * Gets the open nominations
	 * 
	 * @return the open nominations
	 * 
	 */
	@Override
	public Date getOpenNominations() {
		return this.openNomTime;
	}

	/**
	 * Sets the open nominations.
	 *
	 * @param openNomTime the new open nominations
	 */
	public void setOpenNominations(Date openNomTime) {
		this.openNomTime = openNomTime;
	}

	/**
	 * Gets the start date of the election
	 * 
	 * @return the election start date
	 */
	@Override
	public Date getStart() {
		return this.start;
	}

	/**
	 * Gets the end date of the election
	 * 
	 * @return the date of the end of the election
	 * 
	 */
	@Override
	public Date getEnd() {
		return this.end;
	}

	/**
	 * Sets the start.
	 *
	 * @param startDate the
		//TODO for testing purposes 
		//TODO this needs to be changed new start
	 */
	public void setStart(Date startDate){
		this.start = startDate;
	}

	/**
	 * Sets the end.
	 *
	 * @param endDate the new end
	 */
	public void setEnd(Date endDate){
		this.end = endDate;				
	}

	/**
	 * Gets the electorate.
	 *
	 * @return the electorate
	 */
	public Set<Voter> getElectorate() {
		return electorate;
	}

	/**
	 * Sets the electorate.
	 *
	 * @param electorate the new electorate
	 */
	public void setElectorate(Set<Voter> electorate) {
		this.electorate = electorate;	
	}

	/**
	 * Gets the election manager.
	 *
	 * @return the election manager
	 */
	public String getElectionManager() {
		return manager;
	}

	/**
	 * Sets the election manager.
	 *
	 * @param manager the new election manager
	 */
	public void setElectionManager(String manager) {
		this.manager = manager;
	}



	public List<String> getVotes() {
		return votes;
	}


	public void setVotes(List<String> votes) {
		this.votes = votes;
	}
	
	/** Determines whether the an election has the type Referendum 
	 * 
	 * @return true if election type is a referendum
	 * */
	public boolean isReferendum(){
		if (getClass().equals(Referendum.class)){
			return true;
		}
		else{
			return false;
		}
	}

}